/** 
Copyright (c) 2010, Sheikh Abdul Wahid Ahmed
Details @ http://extremecodeworld.codeplex.com/license
**/

using System;
using System.Collections;
using System.Data;
using EXtremecode.DataAccessLayer;
using EXtremecode.Utils;
using System.Text;

namespace EXtremecode.BusinessLayer
{
	/// <summary>
	/// Summary description for BusinessObjectPaper.
	/// </summary>
	public class BusinessObjectPaper
	{
		
		private Hashtable htModifiedValues=new Hashtable();
        private Hashtable htOriginalValues = new Hashtable();
        private Hashtable htUnknownFieldsValues = new Hashtable();
		FieldInfoCollection  fields; //containing fields definition
		
        //new paper
        public BusinessObjectPaper(FieldInfoCollection fields)
		{
			this.fields=fields;
        }

        //clone
        public BusinessObjectPaper(BusinessObjectPaper sourcePaper)
        {
            this.fields = sourcePaper.FieldsDefinitions;

            foreach (string key in sourcePaper.FieldsDefinitions.Keys)
            {

                htOriginalValues.Add(key, sourcePaper[key, true]);
                if (sourcePaper.IsFieldValueChanged(key))
                {
                    htModifiedValues.Add(key, sourcePaper[key]);
                }
                
            }
        }

        

		public virtual object this[string fieldName]
		{
			
            get
			{
                return this[fieldName, false];
			}
			set
			{

                this[fieldName, false] = value;
			}
		}
        public object this[string fieldName, bool originalValue]
        {
            get
            {
                Hashtable ht = null;

                //set appropriate ht.
                if (fields.Contains(fieldName))
                {
                    //--for known fields
                    ht = (!originalValue && htModifiedValues.Contains(fieldName))
                        ? htModifiedValues
                        : htOriginalValues;

                }
                else
                {
                    //--for unknown fields
                    ht = htUnknownFieldsValues;
                }


                return (ht.Contains(fieldName)) ?
                             ht[fieldName] :
                             null;
            }
            set
            {
                if (value == DBNull.Value)
                {
                    value = null;
                }

                //set appropriate ht.
                Hashtable ht = null;
                if (fields.Contains(fieldName))
                {
                    //--for known fields
                    ht = (originalValue)
                        ? htOriginalValues
                        : htModifiedValues;
                }
                else
                {
                    //--for unknown fields
                    ht = htUnknownFieldsValues;
                }



                //update ht with value.
                if (!ht.Contains(fieldName))
                {
                    ht.Add(fieldName, value);
                }
                else
                {
                    ht[fieldName] = value;
                }


            }




        }
		public bool IsFieldValueChanged(string fieldName)
		{
			//if modifiedValue contains key, means value has been changed
			return htModifiedValues.Contains(fieldName);
		}

        public bool IsModified
        {
            get
            {
                return (htModifiedValues.Count > 0);
            }
        }


		public string[] ModifiedKeys
		{
			get
			{
				return  (string[])
					new ArrayList(htModifiedValues.Keys).ToArray(typeof(string));
			}
				
		}

        public string[] UnknownKeys
        {
            get
            {
                return (string[])
                    new ArrayList(htUnknownFieldsValues.Keys).ToArray(typeof(string));
            }

        }

        public string[] OriginalKeys
        {
            get
            {
                return (string[])
                    new ArrayList(htOriginalValues.Keys).ToArray(typeof(string));
            }

        }
		public FieldInfoCollection FieldsDefinitions
		{
			get
			{
				return fields; 
			}
		}

		public void Accept()
		{
			//move modified values to original collection
			foreach(string key in htModifiedValues.Keys)
			{
                if (htOriginalValues.Contains(key))
                {
                    htOriginalValues[key] = htModifiedValues[key];
                }
                else
                {
                    htOriginalValues.Add(key, htModifiedValues[key]);
                }
			}

			//clear modified list.
			htModifiedValues.Clear();
		}

		public void Reject()
		{
			//clear modified list.
			htModifiedValues.Clear();
		}

        public void Clear()
        {
            htUnknownFieldsValues.Clear();
            htModifiedValues.Clear();
            htOriginalValues.Clear();
        }

        public override string ToString()
        {

            //Modified
            StringBuilder sb = new StringBuilder();
            sb.Append("Modified:   ");
            foreach (string key in this.ModifiedKeys)
            {
                sb.Append(string.Format(" {0} = {1} |"
                    , key
                    , (this[key] == null)
                        ? "NULL"
                        : this[key]));
            }

            sb.Append(Environment.NewLine + Environment.NewLine);

            //Original
            sb.Append("Original:   ");
            foreach (string key in this.OriginalKeys)
            {
                sb.Append(string.Format(" {0} = {1} |"
                    , key
                    , (this[key] == null)
                        ? "NULL"
                        : this[key]));
            }

            sb.Append(Environment.NewLine + Environment.NewLine);

            //Unknown
            sb.Append("Unknown:   ");
            foreach (string key in this.UnknownKeys)
            {
                sb.Append(string.Format(" {0} = {1} |"
                    , key
                    , (this[key] == null)
                        ? "NULL"
                        : this[key]));
            }




            return sb.ToString();

        }

        public string ObjectData
        {
            get
            {
                return ToString();
            }
        }

		
	}


}
